//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace OpenLS.Chart.UI
{
    internal abstract class ConeGeometryFactoryBase : MeshGeometryFactory
    {
        protected ConeGeometryFactoryBase(BarDirection direction)
            : base(direction)
        { 
        }

        internal abstract Point3D GetPosition(double theta, double value);

        private  Vector3D GetNormal(double t)
        {

            double category = 2*Math.Cos(t);
            double z = 2*Math.Sin(t);
            return CreateVector(1, category, z);
        }

        private static Point GetTextureCoordinate(double t, double y)
        {
            var m = new Matrix();
            m.Scale(1/(2*Math.PI), -0.5);

            var p = new Point(t, y);
            p = p*m;

            return p;
        }

        protected Bounds3D Bounds;
        protected Bounds TotalValueBounds;

        public override MeshGeometry3D CreateGeometry(Bounds3D bounds, Bounds totalValueBounds2, double floor)
        {
            Bounds = bounds;
            TotalValueBounds = totalValueBounds2;
            const int tDiv = 32;
            const int yDiv = 32;
            double maxTheta = AngleHelper.DegreeToRadian(360.0);
            Bounds totalValueBounds = GetValueBounds(bounds);
            double minValue = totalValueBounds.Low;
            double maxValue = totalValueBounds.High;

            double dt = maxTheta/tDiv;
            double dvalue = (maxValue - minValue)/yDiv;

            var mesh = new MeshGeometry3D();
            int dir = Direction == BarDirection.Column ? 1 : -1;
            if (totalValueBounds.Delta > 0)
            {
                {
                    for (int yi = 0; yi <= yDiv; yi++)
                    {
                        double value = minValue + yi*dvalue;

                        for (int ti = 0; ti <= tDiv; ti++)
                        {
                            double t = ti*dt;

                            mesh.Positions.Add(GetPosition(t, value));
                            mesh.Normals.Add(GetNormal(t));
                            mesh.TextureCoordinates.Add(GetTextureCoordinate(t, value));
                        }
                    }
                }

                for (int yi = 0; yi < yDiv; yi++)
                {
                    for (int ti = 0; ti < tDiv; ti++)
                    {
                        int x0 = ti;
                        int x1 = (ti + 1);
                        int y0 = yi*(tDiv + 1);
                        int y1 = (yi + 1)*(tDiv + 1);
                        if (Direction == BarDirection.Column)
                        {
                            mesh.TriangleIndices.Add(x0 + y0);
                            mesh.TriangleIndices.Add(x0 + y1);
                            mesh.TriangleIndices.Add(x1 + y0);

                            mesh.TriangleIndices.Add(x1 + y0);
                            mesh.TriangleIndices.Add(x0 + y1);
                            mesh.TriangleIndices.Add(x1 + y1);
                        }
                        else
                        {
                            mesh.TriangleIndices.Add(x0 + y0);
                            mesh.TriangleIndices.Add(x1 + y0);
                            mesh.TriangleIndices.Add(x0 + y1);

                            mesh.TriangleIndices.Add(x1 + y0);
                            mesh.TriangleIndices.Add(x1 + y1);
                            mesh.TriangleIndices.Add(x0 + y1);
                            
                        }
                    }
                }
            }
            else
            {
                Tessellator.Tessellate(mesh, CreateVector(1, 0, 0),
                                       DiskTessellator.GetPoints(totalValueBounds.Low, GetCategoryBounds(bounds), bounds.Z, dir, 32, Direction));
            }

            Tessellator.Tessellate(mesh, CreateVector(-1, 0, 0), DiskTessellator.GetPoints(totalValueBounds.Low, GetCategoryBounds(bounds), bounds.Z, -dir, 32, Direction));
            AddTop(mesh);
            mesh.Freeze();
            return mesh;
        }

        protected abstract void AddTop(MeshGeometry3D mesh);

    }
}
    